package com.my.aslife.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.my.aslife.controller.FileController;
import com.my.aslife.mapper.OrdersMapper;
import com.my.aslife.module.common.*;
import com.my.aslife.module.entity.*;
import com.my.aslife.module.entity.dtos.DeductMoneyDto;
import com.my.aslife.module.entity.dtos.OrdersAcceptDto;
import com.my.aslife.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.my.aslife.utils.SnowFlakeUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 订单表 服务实现类
 * </p>
 *
 * @author jobob
 * @since 2022-12-12
 */
@Service
public class OrdersServiceImpl extends ServiceImpl<OrdersMapper, Orders> implements OrdersService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    @Lazy
    private DemandService demandService;

    @Autowired
    private AddressService addressService;

    @Autowired
    private IUserService userService;

    @Autowired
    private EmailService emailService;

    @Autowired
    private FileController fileController;

    @Autowired
    private OrdersMapper ordersMapper;

    @Override
    public ResponseResult queryOrderByOrderId(Long orderId) {
        LambdaQueryWrapper<Orders> lqwOrder = new LambdaQueryWrapper<>();
        lqwOrder.eq(Orders::getId, orderId);
        Orders orders = getOne(lqwOrder);

        return ResponseResult.ok(orders);
    }

    @Override
    public ResponseResult acceptDemand(OrdersAcceptDto ordersAcceptDto) {
        // 将接收任务添加到Redis
        String key = RedisConstant.USER_RUNNER_ACCEPTED + ordersAcceptDto.getDemandKey();
        String task = stringRedisTemplate.opsForValue().get(key);
        // 任务已经被抢
        if (task != null) {
            return ResponseResult.failed(ErrorCode.TASK_ACCEPTED);
        }
        // 抢到任务 && 生成订单任务
        stringRedisTemplate.opsForValue().set(key, " ");

        return generateOrder(ordersAcceptDto, key);
    }

    @Override
    public ResponseResult reminderToDemand(Long orderId) {

        String key = RedisConstant.EMAIL_REMINDER + orderId;
        String emailFlag = stringRedisTemplate.opsForValue().get(key);
        // 只能催单一次
        if (emailFlag != null) {
            return ResponseResult.failed(ErrorCode.NOT_SEND_EMAIL_REMINDER);
        }
        // 获取订单信息得到 runnerId
        Orders order = getById(orderId);
        if (order == null) {
            return ResponseResult.failed(ErrorCode.ERROR_REMINDER);
        }
        Long runnerId = order.getRunnerId();
        // 获取 runner 邮件号
        User userRunner = userService.getById(runnerId);

        // 发送催单邮件
        ResponseResult responseResult = demandService.queryDemandByDemandKey(orderId);
        Demand demand = (Demand) responseResult.getData();
        if (demand == null) {
            return ResponseResult.failed(ErrorCode.ERROR_REMINDER);
        }
        stringRedisTemplate.opsForValue().set(key, " ", RedisConstant.ONE_DAY, TimeUnit.DAYS);
        emailService.sendTextEmail(userRunner.getEmail(), demand);

        return ResponseResult.ok();
    }

    @Override
    public ResponseResult uploadFinishDemandUrl(MultipartFile file) {
        ResponseResult responseResult = fileController.uploadFile(file, "finish-demand");
        String orderId = OrderIdThreadLocal.get();
        ordersMapper.updateOrderStatusIsFinish(Long.valueOf(orderId), new Date());

        demandService.updateOrderStatusIsFinish((String) responseResult.getData(), Long.valueOf(orderId));

        return ResponseResult.ok(responseResult.getData());
    }

    @Override
    @Transactional
    public ResponseResult transferOrder(Long orderId) {
        String key = RedisConstant.USER_TRANSFER_ORDER + orderId;
        String transferFlag = stringRedisTemplate.opsForValue().get(key);
        if (transferFlag != null) {
            return ResponseResult.ok();
        }
        stringRedisTemplate.opsForValue().set(key, " ");
        Long uid = Long.valueOf(UserIdThreadLocal.get());
        ResponseResult queryUserData = userService.queryUserInfoByUID(uid);
        User user = (User) queryUserData.getData();
        if (user.getMoney() < Constant.TRANSFER_MONEY) {
            return ResponseResult.failed(ErrorCode.ERROR_SYSTEM_BUSY);
        }
        DeductMoneyDto deductMoneyDto = new DeductMoneyDto();
        deductMoneyDto.setMoney(Constant.TRANSFER_MONEY);
        deductMoneyDto.setUid(uid);

        TxMoney txMoney = new TxMoney();
        txMoney.setId(SnowFlakeUtil.getId());
        txMoney.setUid(uid);
        txMoney.setCreateTime(new Date());
        txMoney.setFinishTime(new Date());
        txMoney.setMoney(Constant.TRANSFER_MONEY);
        deductMoneyDto.setTxMoney(txMoney);
        userService.deductMoney(deductMoneyDto);
        stringRedisTemplate.delete(RedisConstant.USER_RUNNER_ACCEPTED+ orderId);

        ResponseResult responseResult = this.queryOrderByOrderId(orderId);
        Object data = responseResult.getData();
        if (data == null) {
            return ResponseResult.failed(ErrorCode.ORDERS_IS_NOT_FOUNT);
        }
        Orders orders = (Orders) data;
        orders.setStatus(2);
        updateById(orders);

        ResponseResult responseResultDemand = demandService.queryDemandByDemandKey(orderId);
        Object dataDemand = responseResultDemand.getData();
        if (dataDemand == null) {
            return ResponseResult.failed(ErrorCode.ORDERS_IS_NOT_FOUNT);
        }
        Demand demand = (Demand) dataDemand;
        demand.setRunnerStatus(Short.valueOf(4+""));
        demandService.updateById(demand);

        return ResponseResult.ok();
    }

    @Override
    public ResponseResult selectOrderInfoByPageOrCondition(PageRequestVo pageRequestVo) {

        int c = pageRequestVo.getCurrent();
        int size = pageRequestVo.getPageSize();
        int start = (c - 1) * size;

        List<Orders> ordersList = ordersMapper.selectOrderInfoByPageOrCondition(start, size);

        return ResponseResult.ok(ordersList, count());
    }

    /**
     * @return true 成功生成 false 生成失败
     */
    @Async
    public ResponseResult generateOrder(OrdersAcceptDto ordersAcceptDto, String key){
        ResponseResult responseResult = demandService.queryDemandByDemandKey(ordersAcceptDto.getDemandKey());
        Object object = responseResult.getData();
        // 违规抢单 删除 redis
        if (object == null) {
            stringRedisTemplate.delete(key);
            return ResponseResult.failed(ErrorCode.ILLEGAL_TASK);
        }
        // 获取用户地址
        Address address = addressService.queryAddressByDemandKey(ordersAcceptDto.getDemandKey());
        // 任务不完整
        if (address == null) {
            stringRedisTemplate.delete(key);
            demandService.deleteDemandByAddressKey(ordersAcceptDto.getDemandKey()+"");
            return ResponseResult.failed(ErrorCode.ERROR_TASK_DELETE);
        }
        // 获取跑腿者电话
        User runnerInfo = userService.queryUserById(Integer.parseInt(ordersAcceptDto.getUid() + ""));
        Demand demand = (Demand) object;

        Date date = new Date();

        Orders orders = new Orders();
        orders.setId(ordersAcceptDto.getDemandKey());
        orders.setUserId(Long.valueOf(demand.getUid()));
        orders.setUserPhone(address.getTelNumber());
        orders.setRunnerId(ordersAcceptDto.getUid());
        orders.setRunnerPhone(runnerInfo.getPhone());
        orders.setCreateTime(date);
        orders.setEstimateTime(
                new Date(
                        System.currentTimeMillis() + Constant.ESTIMATE_TIME + (new Random().nextInt(59) * 1000)
                )
        );
        orders.setPayType(Integer.valueOf(demand.getPayType()));
        orders.setStatus(1);
        orders.setMoney(demand.getEmergencyFee() + demand.getMoney());
        save(orders);
        // 设置需求状态 && 配送状态
        demandService.setDemandStatusIsAccepted(ordersAcceptDto.getDemandKey());
        // 将任务添加到 redis list
        String runnerKey = RedisConstant.USER_RUNNER_DEMAND_LIST + ordersAcceptDto.getUid();
        Long size = stringRedisTemplate.opsForZSet().size(runnerKey);
        if (size == null) {
            size = 0L;
        }
        stringRedisTemplate.opsForZSet().add(runnerKey, ordersAcceptDto.getDemandKey()+"", size+1);

        return ResponseResult.ok();
    }
}
